package com.safeluck.floatwindow.camera;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceView;


import com.orhanobut.logger.Logger;
import com.safeluck.floatwindow.MediaArgu;
import com.safeluck.floatwindow.MediaRecordCls;
import com.safeluck.floatwindow.app.MyApplication;
import com.safeluck.floatwindow.bean.GlobalData;
import com.safeluck.floatwindow.usbVideo.AACEncodeConsumer;
import com.safeluck.floatwindow.usbVideo.H264EncodeConsumer;
import com.safeluck.floatwindow.usbVideo.ImageUtil;
import com.safeluck.floatwindow.usbVideo.Mp4MediaMuxer;
import com.safeluck.floatwindow.usbVideo.RecordParams;
import com.safeluck.floatwindow.usbVideo.UsbCameraVideo;
import com.safeluck.floatwindow.usbVideo.WaterMakeUtils;
import com.safeluck.floatwindow.util.MyLog;
import com.safeluck.floatwindow.util.TimeUtil;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
 * @ProjectName: aaa
 * @Package: com.safeluck.floatwindow.camera
 * @ClassName: CameraWrapper
 * @Description: java类作用描述
 * @Author: zhanwei.li
 * @CreateDate: 2021/8/5 17:52
 * @UpdateUser: 更新者
 * @UpdateDate: 2021/8/5 17:52
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */



public class CameraWrapper {

    public  int SRC_VIDEO_HEIGHT = 480;
    public int SRC_VIDEO_WIDTH = 640;

    private static final String TAG = "CameraWrapper";
    private static final boolean DEBUG = true;    // TODO set false on release
    private static CameraWrapper mCameraWrapper;

    private Camera mCamera;
    private Camera.Parameters mCameraParamters;
    private boolean mIsPreviewing = false;
    private CameraPreviewCallback mCameraPreviewCallback;
    private int openCameraId = -1;
    boolean startRecordingFlag = false;
    boolean mIsInitSuccess = false;

    private long usbVideoStartTime;//usbCamera录像开始时间
    private H264EncodeConsumer mH264Consumer;
    private AACEncodeConsumer mAacConsumer;
    private Mp4MediaMuxer mMuxer;

    private UsbCameraVideo.MediaListener mMediaListener;//回掉接口 给FloatSevice

    //是否竖屏
    private boolean isPort;


    public void registerMediaListener(UsbCameraVideo.MediaListener mediaListener){
        this.mMediaListener = mediaListener;
    }

    private CameraWrapper() {
    }

    public static CameraWrapper getInstance() {
        if (mCameraWrapper == null) {
            synchronized (CameraWrapper.class) {
                if (mCameraWrapper == null) {
                    mCameraWrapper = new CameraWrapper();
                }
            }
        }
        return mCameraWrapper;
    }

    public void setScreenPort(boolean isPort) {
        this.isPort = isPort;
    }

    public boolean isPort() {
        return isPort;
    }

    public CameraWrapper setCameraId(int cameraId) {
        this.openCameraId = cameraId;
        return this;
    }

    public boolean doOpenCamera(SurfaceView surfaceView) {
       MyLog.i(TAG, String.format("Camera open.... openCameraId=%s", openCameraId));
        if (openCameraId == -1)
            throw new RuntimeException("openCameraId is -1");

        try {
            mCamera = Camera.open(openCameraId);
        } catch (Exception e) {
            e.printStackTrace();
           MyLog.i(TAG, String.format("doOpenCamera: open fail %s %s", openCameraId, e));
            return false;
        }

        try {
            mCamera.setPreviewDisplay(surfaceView.getHolder());
        } catch (IOException e) {
            e.printStackTrace();
        }
        mCamera.setErrorCallback(new Camera.ErrorCallback() {
            @Override
            public void onError(int error, Camera camera) {
               MyLog.e(TAG,String.format("onError: %s", error) );
            }
        });
       MyLog.i(TAG, "Camera open over....");
        return initCamera();
    }

    /**
     * 开始预览
     */
    public void startPreview() {
        if (!mIsInitSuccess) {
           MyLog.e(TAG, "camera InitSuccess is false");
            return;
        }
        if (!mIsPreviewing) {
//            MediaMuxerRunnable.reStartMuxer();

          /*  String newVideoPath = Utils.getVideoFilePath();
            startRecording(newVideoPath);*/
            mCamera.setPreviewCallbackWithBuffer(mCameraPreviewCallback);
            mCamera.startPreview();

            mIsPreviewing = true;

           MyLog.d(TAG, "camera startPreview");
        } else {
           MyLog.e(TAG, "camera mIsPreviewing is true");
        }
    }

    /**
     * 暂停预览
     */
    public void pausePreview() {
        if (!mIsInitSuccess) {
           MyLog.e(TAG, "camera InitSuccess is false");
            return;
        }
        if (mIsPreviewing) {
//            mCamera.setPreviewCallbackWithBuffer(null);
            mCamera.stopPreview();
            mIsPreviewing = false;
            CameraWrapper.getInstance().stopRecording();

           MyLog.d(TAG, "camera stopPreview");
        } else {
           MyLog.d(TAG, "camera mIsPreviewing is false");
        }
    }

    public boolean isPreview() {
        return mIsPreviewing;
    }

    /**
     * 释放camera 资源
     */
    public void releaseCamera() {
       MyLog.i(TAG, "doStopCamera");
        if (this.mCamera != null) {
//            stopRecording();
//            MuxerManager.getInstance().releaseManager();
            this.mCamera.setPreviewCallback(null);
            this.mCamera.stopPreview();
            this.mIsPreviewing = false;
            this.mCamera.release();
            this.mCamera = null;

            startRecordingFlag = false;
        }
    }

    private boolean initCamera() {
        if (this.mCamera != null) {
            this.mCameraParamters = this.mCamera.getParameters();
            List<Camera.Size> sizes = mCameraParamters.getSupportedPreviewSizes();
            if (DEBUG) {
                for (Camera.Size size : this.mCameraParamters.getSupportedPreviewSizes()) {
                   MyLog.d(TAG, "support preview width=" + size.width + "," + size.height);
                }
            }
            this.mCameraParamters.setPreviewFormat(ImageFormat.NV21);
//            isPort = true;
//            Camera.CameraInfo info = new Camera.CameraInfo();
//            Camera.getCameraInfo(0, info);
//            Log.d(TAG, "摄像头角度 " + info.orientation);
//            int degree = info.orientation + 90;
////            if (MyApplication.getContext().getResources().getConfiguration().orientation
////                    != Configuration.ORIENTATION_LANDSCAPE) {
////                mCameraParamters.set("orientation", "portrait");
////                mCamera.setDisplayOrientation(90);
////                mCameraParamters.setRotation(90);
////                Log.d(TAG, "角度 90");
////            } else {
////                mCameraParamters.set("orientation", "landscape");
////                mCamera.setDisplayOrientation(degree);
////                mCameraParamters.setRotation(degree);
////
////                Log.d(TAG, "角度 ==== " + degree);
////            }
//            mCameraParamters.set("orientation", "landscape");
//            mCamera.setDisplayOrientation(270);
//            mCameraParamters.setRotation(270);
//            Log.d(TAG, "角度 90");

            this.mCamera.setDisplayOrientation(isPort ? 90 : 0);
            this.mCameraParamters.setPreviewSize(SRC_VIDEO_WIDTH, SRC_VIDEO_HEIGHT);

            this.mCamera.setParameters(this.mCameraParamters);

            Camera.Parameters parameters = mCamera.getParameters();
            Camera.Size sz = parameters.getPreviewSize();
           MyLog.i(TAG, "camera width : " + sz.width + "  height  : " + sz.height);
            int bufSize = sz.width * sz.height * 3 / 2;
            mCamera.addCallbackBuffer(new byte[bufSize]);

            if (DEBUG) {

               MyLog.d(TAG, "getMaxNumDetectedFaces =" + this.mCameraParamters.getSupportedVideoSizes());
               MyLog.d(TAG, "getMaxNumDetectedFaces =" + this.mCameraParamters.getMaxNumDetectedFaces());
               MyLog.d(TAG, "getMaxNumFocusAreas =" + this.mCameraParamters.getMaxNumFocusAreas());
               MyLog.d(TAG, "getMaxNumMeteringAreas =" + this.mCameraParamters.getMaxNumMeteringAreas());
                int[] range = new int[2];
                this.mCameraParamters.getPreviewFpsRange(range);
               MyLog.d(TAG, "getPreviewFpsRange =" + Arrays.toString(range));
                List<int[]> fps = this.mCameraParamters.getSupportedPreviewFpsRange();
                if (fps != null)
                    for (int[] f : fps) {
                       MyLog.i(TAG, String.format("initCamera: fps %s", Arrays.toString(f)));
                    }

               MyLog.d(TAG, "getSupportedPreviewFormats =" + this.mCameraParamters.getSupportedPreviewFormats());
               MyLog.d(TAG, "getSupportedSceneModes =" + this.mCameraParamters.getSupportedSceneModes());

            }

            mCameraPreviewCallback = new CameraPreviewCallback();

            mIsInitSuccess = true;
            return true;
        }
        return false;
    }

    /**
     * 开始录制
     */
    public void startRecording(String filePath) {
        startRecordingFlag = true;
        if (DEBUG)
           MyLog.i(TAG, String.format("startRecording: %s %s", startRecordingFlag, filePath));
//        MuxerManager.getInstance().reStartMuxer(filePath);

    }

    /**
     * 暂停录制

     */
    public void pauseRecording() {
        startRecordingFlag = false;
//        MuxerManager.getInstance().pauseMuxer();
    }

    public void resumeRecording() {
        startRecordingFlag = true;
//        MuxerManager.getInstance().resumeMuxer();
    }

    /**
     * 结束录制
     */
    public void stopRecording() {
        startRecordingFlag = false;
        mCamera.stopPreview();
       MyLog.i(TAG, String.format("stopRecording: %s", startRecordingFlag));

//        MuxerManager.getInstance().stopMuxer();

    }
    public static String VIDEO_RECORD_SD_PATH = "/storage/emulated/0/AnYun_VIDEO";
    public static String VIDEO_RECORD_TFCard_PATH = "/storage/sdcard1/AnYun_VIDEO";
    private String videoPath = "";//录像文件存放路径
    private RecordParams recordParams;
    public void setRecordParams(MediaArgu mediaArgu) {
        recordParams = new RecordParams();
        if (mediaArgu!=null){
        recordParams.setRecordDuration(mediaArgu.getRecordTime());
            MediaArgu.ScreenSolution screenSolution = mediaArgu.getM_screen();
            if (screenSolution!=null){
                if (screenSolution.getWidth()>=640){
                    SRC_VIDEO_HEIGHT = 480;
                    SRC_VIDEO_WIDTH = 640;
                }else{
                    SRC_VIDEO_HEIGHT = 240;
                    SRC_VIDEO_WIDTH = 320;
                }
            }else{
                SRC_VIDEO_HEIGHT = 240;
                SRC_VIDEO_WIDTH = 320;
            }

        }else{
            recordParams.setRecordDuration(20);
        }
        if (mediaArgu!=null &&mediaArgu.getTfCardFlag()==1){
            videoPath = VIDEO_RECORD_TFCard_PATH;
        }else{
            videoPath = VIDEO_RECORD_SD_PATH;
        }
        recordParams.setRecordPath(videoPath);
    }

    class CameraPreviewCallback implements Camera.PreviewCallback {

        private CameraPreviewCallback() {
            Log.i(TAG,"开始录像======");
            startRecord(recordParams);
        }

        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
            if (DEBUG)
               Log.i(TAG, String.format("onPreviewFrame: %d t=%s", data.length, Thread.currentThread().getName()));


            //当启动录制的视频把视频源数据加入编码中
//            MuxerManager.getInstance().addVideoFrameData(data);
            if (mH264Consumer!=null){

            mH264Consumer.setRawYuv(Watermarsk(data,SRC_VIDEO_WIDTH,SRC_VIDEO_HEIGHT), SRC_VIDEO_WIDTH,SRC_VIDEO_HEIGHT);
            }
            camera.addCallbackBuffer(data);

        }
    }
    private void startAudioRecord() {
        mAacConsumer = new AACEncodeConsumer();

        mAacConsumer.start();
        // 添加混合器
        if (mMuxer != null) {
            if (mAacConsumer != null) {
                mAacConsumer.setTmpuMuxer(mMuxer);
            }
        }
    }


    ByteArrayOutputStream baos;
    long beginTime = 0L;
    public byte[] Watermarsk(byte []data, int width, int height)
    {


        beginTime = System.currentTimeMillis();


        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        newOpts.inJustDecodeBounds = true;
        YuvImage yuvimage = new YuvImage(
                data,
                ImageFormat.NV21,
               width,
                height,
                null);
        baos = new ByteArrayOutputStream();
        yuvimage.compressToJpeg(new Rect(0, 0, width,height), 100, baos);// 80--JPG图片的质量[0-100],100最高
        byte[] rawImage = baos.toByteArray();
//        将rawImage转换成bitmap
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        Bitmap bitmap = BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length, options);
        bitmap = WaterMakeUtils.convert90(bitmap);

        Bitmap wbmp = WaterMakeUtils.AddWaterMake(MyApplication.getContext(), 0, bitmap, SRC_VIDEO_WIDTH,
                GlobalData.getInstance().parseWaterMaskInfo("school","无", GlobalData.ShareType.STRING),
                GlobalData.getInstance().parseWaterMaskInfo("teacher","无", GlobalData.ShareType.STRING),
                GlobalData.getInstance().parseWaterMaskInfo("student","无", GlobalData.ShareType.STRING),
                GlobalData.getInstance().parseWaterMaskInfo("speed",0.0, GlobalData.ShareType.DOUBLE),
                GlobalData.getInstance().parseWaterMaskInfo("car_license","无", GlobalData.ShareType.STRING),
                GlobalData.getInstance().parseWaterMaskInfo("latitude",29.51228918, GlobalData.ShareType.DOUBLE),
                GlobalData.getInstance().parseWaterMaskInfo("longitude",106.45556208, GlobalData.ShareType.DOUBLE),
                new Date());

        wbmp = WaterMakeUtils.convert0(wbmp);

        byte[] out =ImageUtil.getYUVByBitmap(wbmp);
        Log.i(TAG,"耗时时间="+(System.currentTimeMillis()-beginTime));
        return out;
    }



    /**
     * 开始录制视频
     * @param params
     */
    public void startRecord(final RecordParams params){




                        Logger.d( "run: USBCamera_startRecord");

                        if (params != null) {
                             videoPath = params.getRecordPath();

                            String FILE_NAME = TimeUtil.video_formatTime(System.currentTimeMillis());
                            videoPath+= File.separator+FILE_NAME+".mp4";
                            MyLog.i("UsbCamera video.startRecord filename="+videoPath+"录制时间="+params.getRecordDuration());
                            if (params.getRecordDuration()==0){
                                mMuxer = new Mp4MediaMuxer(videoPath,
                                        10000  * 1000, params.isVoiceClose());
                            }else{
                                mMuxer = new Mp4MediaMuxer(videoPath,
                                        params.getRecordDuration()  * 1000, params.isVoiceClose());
                            }

                            mMuxer.setMp4MediaMuxerLister(new Mp4MediaMuxer.Mp4MediaMuxerLister() {
                                @Override
                                public void result(int type, int errCode, String msg) {
                                    MyLog.i(TAG, "result: "+msg+"errcode="+errCode);
                                    if (errCode == 4){
                                        if (mMediaListener != null){
                                            mMediaListener.stop();
                                        }
                                    }else if (errCode == -3){
                                        //MediaMuxer错误没有到start状态
                                        if (mMediaListener != null){

                                        mMediaListener.ErrState(errCode);
                                        }
                                    }

                                }
                            });
                        }
                        if (mMediaListener != null){
                            mMediaListener.start(0,0,SRC_VIDEO_WIDTH+","+SRC_VIDEO_HEIGHT);
                        }

                        // 启动音频编码线程
                        if (params != null && !params.isVoiceClose()) {
                            MyLog.i(TAG,"启动音频编码线程"+params.isVoiceClose());
                            startAudioRecord();
                        }
                        // 启动视频编码线程
                        startVideoRecord();


        }
    private void startVideoRecord() {
        usbVideoStartTime = System.currentTimeMillis();
        mH264Consumer = new H264EncodeConsumer(SRC_VIDEO_WIDTH , SRC_VIDEO_HEIGHT);

        mH264Consumer.start();
        // 添加混合器
        if (mMuxer != null) {
            if (mH264Consumer != null) {
                mH264Consumer.setTmpuMuxer(mMuxer);
            }
        }
    }


    private void stopVideoRecord() {

        if (mH264Consumer != null) {
            mH264Consumer.exit();
            mH264Consumer.setTmpuMuxer(null);
            try {
                Thread t2 = mH264Consumer;
                mH264Consumer = null;
                if (t2 != null) {
                    t2.stop();
//                    t2.join();
                }
            } catch (Exception e) {
                e.printStackTrace();
                Logger.d("stopVideoRecord exception:"+e.getMessage());
            }

        }
    }

    private void stopAudioRecord() {
        if (mAacConsumer != null) {
            mAacConsumer.exit();
            mAacConsumer.setTmpuMuxer(null);
            try {
                Thread t1 = mAacConsumer;
                mAacConsumer = null;
                if (t1 != null ) {
                    if (t1.isInterrupted())
                        t1.stop();
                }
            } catch (Exception e) {
                e.printStackTrace();
                Logger.d("stopAudioRecord exception:"+e.getMessage());
            }



        }


    }





    /**
     *
     * 停止录制
     */
    public void stopVideoRecord(int err){
        long usbVideoStopTime = System.currentTimeMillis();
        if (err == 4||err==5){

            if (mMediaListener != null){

                long dur = usbVideoStopTime-usbVideoStartTime;
                double dur_second = 1.0f*dur/1000;
                MyLog.d(TAG,"stopPuser: UsbCamera录像时长="+dur_second);

                mMediaListener.recordTime(videoPath,(int)dur_second,err);

            }
        }

        releaseCamera();
        if (mMuxer != null){
            mMuxer.release();
            mMuxer = null;
            MyLog.i("释放音视频编码");
        }

        try {
            stopVideoRecord();
            stopAudioRecord();
        } catch (RuntimeException e) {
            MyLog.i("调用stopVideoRecord+stopAudioRecord之后发生异常，被捕捉到了~~"+e.getMessage());
            e.printStackTrace();
        }




    }



}